/*
 * Copyright 2002-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.context.annotation;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.filter.AbstractTypeHierarchyTraversingFilter;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AspectJTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.RegexPatternTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

/**
 * Parser for the @{@link ComponentScan} annotation.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @author Sam Brannen
 * @since 3.1
 * @see ClassPathBeanDefinitionScanner#scan(String...)
 * @see ComponentScanBeanDefinitionParser
 */

/**
 ComponentScanAnnotationParser 是 Spring 框架中用于解析 @ComponentScan 注解的内部类。
 它负责读取 @ComponentScan 注解的属性，并配置相应的 ClassPathBeanDefinitionScanner 来执行组件扫描。
1 属性
 environment: Environment 类型。用于解析占位符和访问当前运行环境的属性。
 resourceLoader: ResourceLoader 类型。用于加载类路径下的资源。
 beanNameGenerator: BeanNameGenerator 类型。用于为扫描到的 Bean 生成名称。
 registry: BeanDefinitionRegistry 类型。用于注册扫描到的 Bean 定义

 2 方法
 Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass): 核心解析方法。
     参数: componentScan: AnnotationAttributes 类型，代表 @ComponentScan 注解的属性值。 declaringClass: String 类型，表示声明 @ComponentScan 注解的类的全限定名。
	 返回值: Set<BeanDefinitionHolder>，包含扫描到的所有 Bean 定义的持有者。
	 功能: 解析 @ComponentScan 注解的属性，配置 ClassPathBeanDefinitionScanner，并执行扫描。
 List<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes): 辅助方法。
     参数: filterAttributes: AnnotationAttributes 类型，代表 @ComponentScan 注解中 includeFilters 或 excludeFilters 属性中的单个过滤器配置。
	 返回值: List<TypeFilter>，包含根据配置创建的 TypeFilter 对象。
	 功能: 根据过滤器配置（类型、类、表达式等）创建相应的 TypeFilter 实例。

 3. 与其他类和接口的关系
	 ComponentScan: ComponentScanAnnotationParser 专门用于解析此注解。
	 ClassPathBeanDefinitionScanner: ComponentScanAnnotationParser 使用此类来执行实际的类路径扫描和 Bean 定义注册。
	 AnnotationAttributes: 用于封装和访问注解的属性值。
	 BeanDefinitionRegistry: 用于注册扫描到的 Bean 定义。
	 Environment: 用于解析属性占位符和访问环境信息。
	 ResourceLoader: 用于加载类路径资源。
	 BeanNameGenerator: 用于为扫描到的 Bean 生成名称。
	 TypeFilter: 用于定义包含和排除规则。
	 ConfigurationClassPostProcessor: 在处理配置类时，如果遇到 @ComponentScan 注解，会使用 ComponentScanAnnotationParser 来解析它。
 4. 总结
 	ComponentScanAnnotationParser 是一个专门用于解析 @ComponentScan 注解的工具类。
 	它接收注解属性和环境信息，配置一个 ClassPathBeanDefinitionScanner 实例，并触发扫描过程，最终返回扫描到的 Bean 定义。
 	它本身不直接注册 Bean，而是委托给 ClassPathBeanDefinitionScanner 完成。它是 Spring 注解驱动配置体系中的重要一环。
 5. 应用场景
	 @Configuration 类中的 @ComponentScan: 当开发者在配置类上使用 @ComponentScan 注解时，
	 Spring 在处理该配置类时会使用 ComponentScanAnnotationParser 来解析注解并执行扫描。
	 AnnotationConfigApplicationContext: 当使用 AnnotationConfigApplicationContext 并注册带有 @ComponentScan 的配置类时，会间接使用此类。
	 自动配置: Spring Boot 的自动配置机制也可能利用此类来处理自动配置类中的 @ComponentScan 注解。
 */
class ComponentScanAnnotationParser {

	private final Environment environment;

	private final ResourceLoader resourceLoader;

	private final BeanNameGenerator beanNameGenerator;

	private final BeanDefinitionRegistry registry;


	public ComponentScanAnnotationParser(Environment environment, ResourceLoader resourceLoader,
			BeanNameGenerator beanNameGenerator, BeanDefinitionRegistry registry) {

		this.environment = environment;
		this.resourceLoader = resourceLoader;
		this.beanNameGenerator = beanNameGenerator;
		this.registry = registry;
	}


	/**
	 * @param componentScan 表示@ComponentScan注解的属性值
	 * @param declaringClass 表示@ComponentScan注解所在的类
	 * @return
	 */
	public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {

		ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
				componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

		Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
		boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
		// 默认为AnnotationBeanNameGenerator
		scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
				BeanUtils.instantiateClass(generatorClass));

		ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
		if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
			scanner.setScopedProxyMode(scopedProxyMode);
		}
		else {
			Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
			scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
		}

		scanner.setResourcePattern(componentScan.getString("resourcePattern"));

		for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
			for (TypeFilter typeFilter : typeFiltersFor(filter)) {
				scanner.addIncludeFilter(typeFilter);
			}
		}
		for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
			for (TypeFilter typeFilter : typeFiltersFor(filter)) {
				scanner.addExcludeFilter(typeFilter);
			}
		}

		//将扫描出来的beanDefinition的设置是否懒加载
		boolean lazyInit = componentScan.getBoolean("lazyInit");
		if (lazyInit) {
			scanner.getBeanDefinitionDefaults().setLazyInit(true);
		}

		Set<String> basePackages = new LinkedHashSet<>();
		String[] basePackagesArray = componentScan.getStringArray("basePackages");
		for (String pkg : basePackagesArray) {
			String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
					ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
			Collections.addAll(basePackages, tokenized);
		}
		for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
			basePackages.add(ClassUtils.getPackageName(clazz));
		}
		if (basePackages.isEmpty()) {
			basePackages.add(ClassUtils.getPackageName(declaringClass));
		}

		scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
			@Override
			protected boolean matchClassName(String className) {
				return declaringClass.equals(className);
			}
		});
		return scanner.doScan(StringUtils.toStringArray(basePackages));
	}

	private List<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes) {
		List<TypeFilter> typeFilters = new ArrayList<>();
		FilterType filterType = filterAttributes.getEnum("type");

		for (Class<?> filterClass : filterAttributes.getClassArray("classes")) {
			switch (filterType) {
				//匹配带有特定注解的类。
				case ANNOTATION:
					Assert.isAssignable(Annotation.class, filterClass,
							"@ComponentScan ANNOTATION type filter requires an annotation type");
					@SuppressWarnings("unchecked")
					Class<Annotation> annotationType = (Class<Annotation>) filterClass;
					typeFilters.add(new AnnotationTypeFilter(annotationType));
					break;
					//匹配指定类型或其子类实现类。
				case ASSIGNABLE_TYPE:
					typeFilters.add(new AssignableTypeFilter(filterClass));
					break;
					//通过自定义TypeFilter方式匹配
				case CUSTOM:
					Assert.isAssignable(TypeFilter.class, filterClass,
							"@ComponentScan CUSTOM type filter requires a TypeFilter implementation");

					TypeFilter filter = ParserStrategyUtils.instantiateClass(filterClass, TypeFilter.class,
							this.environment, this.resourceLoader, this.registry);
					typeFilters.add(filter);
					break;
				default:
					throw new IllegalArgumentException("Filter type not supported with Class value: " + filterType);
			}
		}

		for (String expression : filterAttributes.getStringArray("pattern")) {
			switch (filterType) {
				//aspectj方式匹配，比如"com.example..*Service+"
				case ASPECTJ:
					typeFilters.add(new AspectJTypeFilter(expression, this.resourceLoader.getClassLoader()));
					break;
				//正则方式匹配，比如"com.example.*"
				case REGEX:
					typeFilters.add(new RegexPatternTypeFilter(Pattern.compile(expression)));
					break;
				default:
					throw new IllegalArgumentException("Filter type not supported with String pattern: " + filterType);
			}
		}

		return typeFilters;
	}

}
